﻿using System;
using System.Text;

namespace Basic
{
    /// <summary>
    /// 临时StringBuilder缓存管理器
    /// 管理的StringBuilder的生命周期只有一帧，禁止缓存
    /// 必须通过GetStringAndRelease获取StringBuilder内的字符串，并让TempTempStringBuilderCache回收StringBuilder
    /// </summary>
    public static class TempStringBuilderCache
    {
        private const int CACHE_COUNT = 4;
        private const int DEFAULT_CAPACITY = 256;
        private const int MAX_CAPACITY = DEFAULT_CAPACITY * 4;

        /// <summary>
        /// 线程唯一
        /// </summary>
        [ThreadStatic]
        static bool[] _status = new bool[CACHE_COUNT] { false, false, false, false };    // true: _caches内，存有有效的未被使用的StringBuilder
        [ThreadStatic]
        static StringBuilder[] _caches = new StringBuilder[CACHE_COUNT] { null, null, null, null };
        [ThreadStatic]
        static int _index = 0;

        static int acquireCount = 0;
        static int releaseCount = 0;

        /// <summary>
        /// Acquire
        /// 申请到的StringBuilder的生命周期必须只有一帧，且必须通过GetStringAndRelease获取其内的字符串并让TempStringBuilderCache回收StringBuilder
        /// 禁止缓存申请到的StringBuilder
        /// </summary>
        /// <param name="capacity"></param>
        /// <returns></returns>
        public static StringBuilder Acquire(int capacity = 256)
        {
            acquireCount++;

            if (capacity > MAX_CAPACITY)
            {
                return new StringBuilder(capacity);
            }

            StringBuilder sb = null;
            if (_caches[_index] == null || !_status[_index])
            {
                _caches[_index] = new StringBuilder(capacity > DEFAULT_CAPACITY ? MAX_CAPACITY : DEFAULT_CAPACITY);
            }
            sb = _caches[_index];

            _status[_index] = false;
            _index = (_index + 1) % CACHE_COUNT;

            return sb;
        }

        /// <summary>
        /// GetStringAndRelease
        /// 获取StringBuilder内的字符串，并让TempStringBuilderCache回收StringBuilder
        /// </summary>
        /// <param name="sb"></param>
        /// <returns></returns>
        public static string GetStringAndRelease(StringBuilder sb)
        {
            releaseCount++;

            string str = sb.ToString();
            for (int i = 0; i < CACHE_COUNT; ++i)
            {
                if (sb == _caches[i])
                {
                    sb.Clear();
                    _caches[i] = sb.Capacity > MAX_CAPACITY ? null : sb;
                    _status[i] = _caches[i] != null;
                    break;
                }
            }
            return str;
        }
    }
}
